package com.fh.controller.system.weixin.wxutil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
//import org.marker.weixin.MySecurity;

import com.fh.controller.system.weixin.resp.AccessToken;
import com.fh.controller.system.weixin.wxmenu.MenuManager;
import com.fh.util.MiceConfig;
import com.fh.util.FishingSingle;

public class WeixinUtil {
	public static String appId = "";
	// 应用密钥
	public static String appsecret = "";

	public static String getAppId() {
		MenuManager loadProp = new MenuManager();
		InputStream in = loadProp.getClass().getResourceAsStream(
				"/words.properties");
		Properties prop = new Properties();
		try {
			prop.load(in);
			appId = prop.getProperty("wd_appID");
			in.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			prop.clear();
		}
		return appId;
	}

	public static void setAppId(String appId) {
		WeixinUtil.appId = appId;
	}

	public static String getAppsecret() {
		MenuManager loadProp = new MenuManager();
		InputStream in = loadProp.getClass().getResourceAsStream(
				"/words.properties");
		Properties prop = new Properties();
		try {
			prop.load(in);
			appsecret = prop.getProperty("wd_appsecret");
			in.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			prop.clear();
		}
		return appsecret;
	}

	public static void setAppsecret(String appsecret) {
		WeixinUtil.appsecret = appsecret;
	}

	private static Logger logger = Logger.getLogger(WeixinUtil.class);// 日志
	public static final String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

	// 网页授权access_token
	public static final String html_access_token = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";

	public static AccessToken getAccessToken(String appid, String appsecret) {
		AccessToken accessToken = null;
		String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"
				.replace("APPID", appid).replace("APPSECRET", appsecret);
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);

		if (jsonObject != null) {
			try {
				accessToken = new AccessToken();
				accessToken.setToken(jsonObject.getString("access_token"));
				accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
			} catch (JSONException e) {
				accessToken = null;
				logger.error("获取token失败 errcode:{} errmsg:{}"
						+ Integer.valueOf(jsonObject.getInt("errcode"))
						+ jsonObject.getString("errmsg"));
			}
		}
		return accessToken;
	}

	public static void main(String[] args) {
		 //JSONObject jb = htmlAccessToken("0314d7f87e8b8f297d6a31e1a4a7ce43", "wx2a31085e3aab06ce", "312338e779b8eb9713c682a0998b345b");
		String openId = "owDGYs9b6df7JzxCuIwQbyMKbzCI";
		getUserInfo("0314d7f87e8b8f297d6a31e1a4a7ce43");
		
	}

	/**
	 * 根据code 获取用户id
	 * 
	 * @param code
	 * @return
	 */
	public static String getOpenId(String code) {
		JSONObject htmlAccessToken = htmlAccessToken(code,
				WeixinUtil.getAppId(), WeixinUtil.getAppsecret());
		return htmlAccessToken.getString("openid");
	}

	/**
	 * 根据code获取用户信息
	 * 
	 * @param code
	 * @return {"openid":"o5UkCj3pHi1oG3oa_9MIxa8mWFU0",
	 *         "nickname":"沈朝","sex":1,"language":"zh_CN",
	 *         "city":"海淀","province":"北京","country":"中国", "headimgurl":
	 *         "http://wx.qlogo.cn/mmopen/O9bMsliaDL8iacImB8oSTY6WjqY0aHic6sF5M538DVP0VFE7Zbe0AzmCQfVzibPYBgcGto87sCIrLUP7cHJLrACSLWVGyUztbqcia/0"
	 *         , "privilege":[]}
	 */
	public static JSONObject getUserInfo(String code) {
		JSONObject htmlAccessToken = htmlAccessToken(code,
				WeixinUtil.getAppId(), WeixinUtil.getAppsecret());
		System.out.println(htmlAccessToken);
		// 拉取用户信息
		JSONObject accessUserInfo = accessUserInfo(htmlAccessToken);
		return accessUserInfo;

	}

	/**
	 * 根据授权code ，appId，secret获取access_token和openid
	 * 
	 * @param code
	 *            授权code
	 * @param appId
	 *            应用id
	 * @param secret
	 *            应用密钥
	 * @return 正确格式： { "access_token":"ACCESS_TOKEN", "expires_in":7200,
	 *         "refresh_token":"REFRESH_TOKEN", "openid":"OPENID",
	 *         "scope":"SCOPE" }
	 */
	private static JSONObject htmlAccessToken(String code, String appId,
			String secret) {
		logger.info("网页授权access_token...");
		// 替换请求参数
		String replaceUrl = html_access_token.replace("APPID", appId)
				.replace("SECRET", secret).replace("CODE", code);
		// 发起请求
		JSONObject result = httpRequest(replaceUrl, "GET", null);
		logger.info(result);
		return result;
	}

	// 拉取用户信息
	public static final String access_user_info = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

	/**
	 * 授权成功，获取用户详细信息
	 * 
	 * @param jsonObject
	 *            授权信息： { "access_token":"ACCESS_TOKEN", "expires_in":7200,
	 *            "refresh_token":"REFRESH_TOKEN", "openid":"OPENID",
	 *            "scope":"SCOPE" }
	 * @return 正确格式：{ "openid":" OPENID", " nickname": NICKNAME, "sex":"1",
	 *         "province":"PROVINCE" "city":"CITY", "country":"COUNTRY",
	 *         "headimgurl":
	 *         "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46"
	 *         , "privilege":[ "PRIVILEGE1" "PRIVILEGE2" ], "unionid":
	 *         "o6_bmasdasdsad6_2sgVt7hMZOPfL" }
	 */
	private static JSONObject accessUserInfo(JSONObject jsonObject) {
		logger.info("拉取用户信息");
		JSONObject result = null;
		if (null != jsonObject) {
			// 网页授权access_token
			String access_token = jsonObject.getString("access_token");
			// 用户的唯一标识
			String openid = jsonObject.getString("openid");
			// 替换请求参数
			String replaceUrl = access_user_info.replace("ACCESS_TOKEN",
					access_token).replace("OPENID", openid);
			// 发起请求
			result = httpRequest(replaceUrl, "GET", null);
		} else {
			throw new RuntimeException("授权失败。");
		}
		logger.info(result);
		return result;
	}

	// JS-SDK使用权限签名算法接口
	public static final String jsApi = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";

	/**
	 * appId : 'wx2a31085e3aab06ce', timestamp : 1414587457, nonceStr : 'gxz',
	 * signature : '509e38ceaed248d8c6c466975d9f9b348fdb9e52',
	 * 
	 * @return jsapi
	 */
	public static String jsApi() {
		// 存储凭证和生成时间
		FishingSingle instance = FishingSingle.instance;
		// 生成时间
		instance.setJsGenerateTime(new Date());
		logger.info("获取js加密凭证。。。");
		AccessToken accessToken = getAccessToken(getAppId(), getAppsecret());
		String replaceUrl = jsApi.replace("ACCESS_TOKEN",
				accessToken.getToken());

		JSONObject json = httpRequest(replaceUrl, "GET", null);
		// 存储凭证
		instance.setJsTicket(json.getString("ticket"));
		return json.getString("ticket");
	}

	/**
	 * 微信js sdk 签名
	 * 
	 * @param url
	 *            页面url
	 * @return
	 */
	public static Map<String, Object> getSignature(String url) {
		Map<String, Object> map = new HashMap<String, Object>();
		String ticket = null;
		// 存储凭证和生成时间
		FishingSingle instance = FishingSingle.instance;
		if (null != instance.getJsGenerateTime()) {
			Date currentTime = new Date();
			// 计算时间差
			long time = ((currentTime.getTime() - instance.getJsGenerateTime()
					.getTime()) / 1000);
			// ticket有效时间7200秒
			if (time >= 7100) {
				// 获取js凭证
				ticket = WeixinUtil.jsApi();
			} else {
				ticket = instance.getJsTicket();
			}
		} else {
			// 获取js凭证
			ticket = WeixinUtil.jsApi();
		}
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("jsapi_ticket", ticket);
		paramsMap.put("timestamp", System.currentTimeMillis());
		paramsMap.put("noncestr", "weixin");
		paramsMap.put("url", url);
		// 排序后的结果
		String listStr = createLinkString(paramsMap);
		logger.info("排序后..." + listStr);
		// SHA-1加密
		/*//String tmpStr = new MySecurity().encode(listStr, MySecurity.SHA_1);
		logger.info("SHA-1加密后：" + tmpStr);
		map.put("appId", WeixinUtil.appId);
		map.put("timestamp", paramsMap.get("timestamp"));
		map.put("nonceStr", paramsMap.get("noncestr"));
		map.put("signature", tmpStr);*/
		return map;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	public static String createLinkString(Map<String, Object> params) {

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			Object value = params.get(key);

			if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}

	public static JSONObject httpRequest(String requestUrl,
			String requestMethod, String outputStr) {
		JSONObject jsonObject = null;
		StringBuffer buffer = new StringBuffer();
		try {
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new SecureRandom());

			SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url
					.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);

			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod)) {
				httpUrlConn.connect();
			}

			if (outputStr != null) {
				OutputStream outputStream = httpUrlConn.getOutputStream();

				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			InputStream inputStream = httpUrlConn.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(
					inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader);

			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();

			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
			jsonObject = JSONObject.fromObject(buffer.toString());
		} catch (ConnectException ce) {
			logger.error("Weixin server connection timed out.");
		} catch (Exception e) {
			logger.error("https request error:{}", e);
		}
		return jsonObject;
	}
}
